home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
awe2-0_1.lha
/
awe2-0.1
/
Src
/
RCS
/
HardwareCpu.cc,v
< prev
next >
Wrap
Text File
|
1988-09-28
|
28KB
|
1,286 lines
head 1.3;
access ;
symbols ;
locks ; strict;
comment @@;
1.3
date 88.09.28.22.13.27; author grunwald; state Exp;
branches ;
next 1.2;
1.2
date 88.09.21.20.51.32; author grunwald; state Exp;
branches ;
next 1.1;
1.1
date 88.09.18.16.42.24; author grunwald; state Exp;
branches ;
next ;
desc
@@
1.3
log
@*** empty log message ***
@
text
@#include "HardwareCpu.h"
#include "HardSpinLock.h"
#include "HardBarrier.h"
#include "HardFetchAndOp.h"
#include "AwesimeHeap.h"
#include "Thread.h"
#include "HeapScheduler.h"
#include "ReserveByException.h"
#include <math.h>
//
// Things left to do:
//
// + Add instrumentation code ifdef'd on INSTRUMENT, to measure
// the following: number of threads exec'd per clock-tick,
// time spent waiting for other CPUS, (what else?)
//
// + Make all the debug stuff be conditional on DEBUG being defined
//
// + Chunk the CurrentEventsList into a pile for each CPU. A
// CPU draws first from their own pile, and then from the
// piles of others.
// Advantages: reduces lock contention
// increase cache locality
//
// Disadvantages: Pain to implement
// ** DONE **
//
// + Make the ThreadHeap really use the Gnu PairingHeap structure.
// Doug Lea added an iterator class & other enhancements.
//
// + Capture signals, transfer them to an Exception class. Can
// use this to implement time-slices & the like, as well as....
//
// + Put in ``addCpu'' and ``removeCpu'' calls to HardwareCpu.
// This would allow run-time addition/removal of CPUS, so
// you can tailor your program to system
// This is tricky. Should probably do it when you
// advance the clock, but it'll be tricky to get all
// the CPUs to agree on the barrier height for the
// rendezvous. Also might complicate the ``distinct
// pools of threads per cpu''.
//
#ifndef umax
const static int MaxHardwareCpus = 1;
#else
const static int MaxHardwareCpus = 20;
#endif
int HardwareCpus;
HardwareCpu *ThisCpu;
static HardBarrier CpuBarrier(0);
//
// PendingEventsLock, CurrentEventsLock and TimeAdvanceCounterLock
// must be acquired in that order, and releaseed in the reverse order.
//
static HardSpinLock cerrLock;
//
// The count of all all current events
//
static HardFetchAndOp GlobalCurrentEventsCounter(0);
//
// A currentEvents pile for each processor. The count is only correct
// if you've res'd the spin lock -- it's used as a guess.
//
static HardSpinLock CurrentEventsLock[MaxHardwareCpus];
static int CurrentEventsCounter[MaxHardwareCpus];
static ThreadContainer *CurrentEvents[MaxHardwareCpus];
//
// The PendingEvents queue is private to each processor
//
static AwesimeHeap *PendingEvents[MaxHardwareCpus];
static int SimulationTerminated = 0;
double CurrentSimulatedTime = 0.0;
static HardFetchAndOp TimeAdvanceCounter(0);
//
// This can't be private, or we won't see all the action
//
int HardwareDebugFlag = 0;
HardwareCpu::HardwareCpu(int debug) : systemContext(0, 0)
{
currentThread = 0;
iYam = 0;
pid = 0;
HardwareDebugFlag = debug;
allocateEventStructures(0);
}
HardwareCpu::~HardwareCpu()
{
}
void
HardwareCpu::debug(int newdebug)
{
HardwareDebugFlag = newdebug;
}
int
HardwareCpu::debug()
{
return(HardwareDebugFlag);
}
void
HardwareCpu::rendezvous()
{
CpuBarrier.rendezvous();
}
void
HardwareCpu::allocateEventStructures(int newIYam)
{
iYam = newIYam;
sprintf(nameSpace, "[HardwareCpu-%d] ", iYam);
name = nameSpace;
CurrentEventsCounter[iYam] = 0;
CurrentEvents[iYam] = AllocateHardwareCurrentEventsStructure();
PendingEvents[iYam] = new AwesimeHeap(128);
myCurrentEvents = CurrentEvents[iYam];
myCurrentEventsLock = &CurrentEventsLock[iYam];
myPendingEvents = PendingEvents[iYam];
}
void
HardwareCpu::deallocateEventStructures()
{
myCurrentEventsLock -> reserve();
//
// Move remaining events to another queue
//
while ( CurrentEventsCounter[iYam] == 0 ) {
CurrentEventsLock[0].reserve();
assert(CurrentEvents[0] != 0);
CurrentEvents[0] -> add( myCurrentEvents -> remove() );
CurrentEventsCounter[0]++;
CurrentEventsCounter[iYam]--;
CurrentEventsLock[0].release();
}
delete myCurrentEvents;
myCurrentEvents = 0;
CurrentEvents[iYam] = 0;
CurrentEventsCounter[iYam] = 0;
myCurrentEventsLock -> release();
while ( ! myPendingEvents -> isEmpty() ) {
assert(PendingEvents[0] != 0);
AwesimeHeapItem item;
if (myPendingEvents -> remove(item)) {
PendingEvents[0] -> add( item );
}
}
delete myPendingEvents;
myPendingEvents = 0;
PendingEvents[iYam] = 0;
}
void
HardwareCpu::fireItUp(int cpus, unsigned shared)
{
assert(cpus > 0);
if ( cpus > MaxHardwareCpus ) {
cpus = MaxHardwareCpus;
}
HardwareCpus = cpus;
ThisCpu = this;
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "Allocate " << shared << " bytes of shared memory\n";
cerrLock.release();
}
#endif /* NDEBUG */
extern void SharedMemoryInit( unsigned );
SharedMemoryInit( shared );
//
// Spawn the children, giving each a unique number from 0..(cpus-1).
// The first child gets id (cpus-1), and the original process gets 0.
//
iYam = 0;
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "Allocate " << HardwareCpus << "cpus\n";
cerrLock.release();
}
#endif /* NDEBUG */
CpuBarrier.height(HardwareCpus);
for (int whoAmI = 1; whoAmI < HardwareCpus; whoAmI++) {
if (iYam == 0) {
int pid = fork();
if (pid == 0) { // child
allocateEventStructures(whoAmI);
break;
}
}
}
pid = getpid();
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "I am now id " << iYam << " and pid " << pid <<" \n";
cerrLock.release();
}
#endif /* NDEBUG */
rendezvous();
}
void
HardwareCpu::coolItDown()
{
rendezvous();
if (iYam > 0) {
cerrLock.reserve();
cerr << name << "exit";
cerrLock.release();
_exit(0);
}
else {
//
// reap the dead children. This way we know they are all dead.
// The caller can then safely exit.
//
while (HardwareCpus > 1) {
int pid = wait(0);
if (pid == -1) {
perror("wait");
break;
}
HardwareCpus--;
}
//
// In case of break in above loop
//
HardwareCpus = 1;
//
// In case we call rendezvous again
//
CpuBarrier.height(HardwareCpus);
}
}
void
HardwareCpu::add(Thread *who, double when)
{
if (when <= 0) {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << " add " << hex(long(who)) << " to current\n";
cerrLock.release();
}
#endif /* NDEBUG */
//
// Add them to the list of current events
//
myCurrentEventsLock -> reserve();
myCurrentEvents -> add( who );
CurrentEventsCounter[iYam]++;
myCurrentEventsLock -> release();
GlobalCurrentEventsCounter.add(1);
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << " giving " << CurrentEventsCounter[iYam];
cerr << " local and " << GlobalCurrentEventsCounter.add(0);
cerr << " global\n";
cerrLock.release();
}
#endif /* NDEBUG */
}
else {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << " add " << hex(long(who)) << " to pending\n";
cerrLock.release();
}
#endif /* NDEBUG */
//
// Add them to pending events
//
when += CurrentSimulatedTime;
myPendingEvents->add( AwesimeHeapItem(when, who) );
}
}
//
// Advance time. Assumes all other CPUs are idle, so no locking
// on event structures is needed.
//
void
HardwareCpu::advanceTime()
{
//
// Find the minimum time over all pending event piles
//
double when = MAXFLOAT;
bool validItem = FALSE;
for (int i = 0; i < HardwareCpus; i++ ) {
AwesimeHeap *p = PendingEvents[i];
if ( ! p -> isEmpty() ) {
double hapAt = p -> item( p -> minItem() ).key();
if (hapAt < when) {
when = hapAt;
validItem = TRUE;
}
}
}
if ( !validItem ) {
SimulationTerminated = 1;
}
else {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << " ADVANCE TIME TO " << when << "\n" ;
cerrLock.release();
}
#endif /* NDEBUG */
assert( CurrentSimulatedTime <= when );
CurrentSimulatedTime = when;
}
//
// Should be safe to do this -- everyone is waiting for the master
// to rendezvous
//
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "Clear TimeAdvanceCounter\n";
cerrLock.release();
}
#endif /* NDEBUG */
TimeAdvanceCounter.set(0);
}
Thread *
HardwareCpu::remove()
{
//
// Check to see if there's a current event. This gets tricky, because
// we may not want to wait any more if another event comes in.
//
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << " try to remove thread\n";
cerrLock.release();
}
#endif /* NDEBUG */
Thread *threadToExecute = 0;
do {
//
// System stopped?
//
if (SimulationTerminated) {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << " Simulation terminated\n" ;
cerrLock.release();
}
#endif /* NDEBUG */
return(0);
}
//
// I got something to do?
//
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name;
cerr << "Check my own current events pile";
cerr << " (" << CurrentEventsCounter[iYam] << ")\n";
cerrLock.release();
}
#endif /* NDEBUG */
myCurrentEventsLock -> reserve();
if ( CurrentEventsCounter[iYam] > 0 ) {
threadToExecute = myCurrentEvents -> remove();
CurrentEventsCounter[iYam] --;
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name;
cerr << "Found something, now bump events counter\n";
cerrLock.release();
}
#endif /* NDEBUG */
GlobalCurrentEventsCounter.add(-1);
}
myCurrentEventsLock -> release();
if (threadToExecute == 0) {
//
// Maybe someone else has something to do?
//
while ( threadToExecute == 0 && GlobalCurrentEventsCounter.add(0) > 0 ) {
#ifndef NDEBUG
if ( HardwareDebugFlag ) {
cerrLock.reserve();
cerr << name << " Global Events = ";
cerr << GlobalCurrentEventsCounter.add(0) << "\n";;
cerrLock.release();
}
#endif /* NDEBUG */
int ask = iYam;
do {
ask++;
if ( ask >= HardwareCpus ) { // wrap around for fairness
ask = 0;
}
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "Ask " << ask << " about events \n";
cerrLock.release();
}
#endif /* NDEBUG */
//
// Note that were *not* locking before looking
// at CurrentEventsCount -- we treat this as a *guess*
// before bothering to lonk on it.
//
if ( CurrentEventsCounter[ask] > 0) {
CurrentEventsLock[ask].reserve();
if ( CurrentEventsCounter[ask] > 0) {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name;
cerr << "Found one in " << ask << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
threadToExecute = CurrentEvents[ask] -> remove();
GlobalCurrentEventsCounter.add(-1);
CurrentEventsCounter[ask]--;
}
CurrentEventsLock[ask].release();
}
} while (ask != iYam && threadToExecute == 0);
if ( threadToExecute == 0 ) {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name;
cerr << "Did not find anything, may look again";
cerr << " cnt = ";
cerr << GlobalCurrentEventsCounter.add(0);
cerr << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
}
}
if ( threadToExecute == 0 ) {
//
// Ok, we have decided that there is nothing for us to do,
// and there is nothing for anyone else to do either (maybe).
// So we need to decide if we are going to advance time or not.
//
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name;
cerr << "Did not find anything, maybe rendezvous\n";
cerrLock.release();
}
#endif /* NDEBUG */
int timeAdvanceWas = TimeAdvanceCounter.add(1);
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "increment time advance counter to ";
cerr << timeAdvanceWas << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
assert(timeAdvanceWas <= HardwareCpus);
//
// Now, wait for either of TimeAdvanceCounter == HardwareCpus,
// for a new event
int goAdvanceTime = 0;
int lookForEvent = 0;
do {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name;
cerr << "reserve GlobalCurrentEventsCounter";
cerr << " and TimeAdvanceCounter\n";
cerrLock.release();
}
#endif /* NDEBUG */
int global = GlobalCurrentEventsCounter.add(0);
timeAdvanceWas = TimeAdvanceCounter.add(0);
lookForEvent = global > 0 || SimulationTerminated;
goAdvanceTime = !lookForEvent
&& timeAdvanceWas == HardwareCpus;
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "lookForEvent = " << int(lookForEvent);
cerr << " and goAdvanceTime == " << int(goAdvanceTime);
cerr << " and TimeAdvanceCounter = " << timeAdvanceWas;
cerr << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
if (lookForEvent) {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "decrement TimeAdvanceCounter\n";
cerrLock.release();
}
#endif /* NDEBUG */
//
// Is this a race? I don not think so. I think we need
// to put our iron out of the file above & then
// then put it back in if we decide that we want
// to loop around.
//
TimeAdvanceCounter.add(-1);
}
} while ( !( goAdvanceTime || lookForEvent ) );
assert( (goAdvanceTime && !lookForEvent)
|| (lookForEvent && !goAdvanceTime) );
if (lookForEvent) {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "decided to look for event\n";
cerrLock.release();
}
#endif /* NDEBUG */
}
else {
rendezvous();
//
// Nothing is locked at this point.
//
if (iYam == 0) {
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "rendezvous to advance time\n";
cerrLock.release();
}
#endif /* NDEBUG */
advanceTime();
}
//
// Why the second rendezvous?
// If tasks are priority ordered, we want to be able
// to pull them out, order them & then start.
//
// Also, advance time depends on this.
//
rendezvous();
//
// Now that we know the time of the minimum entry in the
// heap, remove all the events which occur at that time
// or before that time (actually, that is an error).
//
// Each process does its own work to reduce overhead.
// We keep track of how many processes were added to
// the current events queue and then bump the global
// events count by that amout.
//
// This canot cause race conditions because we only
// use this info in the rendevzous to advance time
// code above, and not all cpus will be there yet
// (i.e. the current cpu is not there)
//
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "Move pending to active\n";
cerrLock.release();
}
#endif /* NDEBUG */
AwesimeHeapItem item;
AwesimeHeap *p = myPendingEvents;
ThreadContainer *c = myCurrentEvents;
int added = 0;
CurrentEventsLock[iYam].reserve();
for (AwesimeHeapIndex index = p -> minItem();
index != AwesimeHeapNull
&& p -> item(index).key() <= CurrentSimulatedTime;
index = p -> minItem() )
{
bool removed = p -> remove(item);
assert( removed );
c -> add((Thread *) item.ptr());
added++;
}
CurrentEventsCounter[iYam] += added;
GlobalCurrentEventsCounter.add(added);
CurrentEventsLock[iYam].release();
}
}
}
} while (threadToExecute == 0);
assert( threadToExecute != 0 ) ;
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "find " << hex(long(threadToExecute)) << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
return( threadToExecute );
}
void
HardwareCpu::terminateSimulation()
{
SimulationTerminated = 1;
}
//
// Exception handlers
//
void
HardwareCpu::raise()
{
assert(currentThread != 0);
currentThread -> pContext.switchContext( &systemContext );
}
void
HardwareCpu::delayException( double howLong )
{
//
// This duplicates some code in add -- it is done here to speed things
// up.
//
#ifndef NDEBUG
if ( HardwareDebugFlag ) {
cerrLock.reserve();
cerr << name << " delay context for " << howLong << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
if ( howLong > 0 ) {
#ifndef NDEBUG
if ( HardwareDebugFlag ) {
cerrLock.reserve();
cerr << name << " place on pending queue\n";
cerrLock.release();
}
#endif /* NDEBUG */
assert(currentThread != 0);
howLong += CurrentSimulatedTime;
myPendingEvents->add( AwesimeHeapItem(howLong, currentThread) );
myCurrentEventsLock -> reserve();
if ( CurrentEventsCounter[iYam] > 0 ) {
#ifndef NDEBUG
if ( HardwareDebugFlag ) {
cerrLock.reserve();
cerr << name << " CurrentEventsCount = ";
cerr << CurrentEventsCounter[iYam] << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
Thread *from = currentThread;
currentThread = myCurrentEvents -> remove();
CurrentEventsCounter[iYam]--;
GlobalCurrentEventsCounter.add(-1);
myCurrentEventsLock -> release();
#ifndef NDEBUG
if ( HardwareDebugFlag ) {
cerrLock.reserve();
cerr << name << " and switch to ";
cerr << hex(long(currentThread)) << "\n";
cerr << *currentThread;
cerrLock.release();
}
#endif /* NDEBUG */
from -> pContext.switchContext ( &( currentThread -> pContext ) );
//
// The contact that called delayException will resume here
//
}
else {
//
// Unable to simply call remove(), because we might advance time
// or something. However, we have put our self into the pending
// queue, so we simply need to find a new context.
//
myCurrentEventsLock -> release();
#ifndef NDEBUG
if ( HardwareDebugFlag ) {
cerrLock.reserve();
cerr << name << " let CPU switch contexts\n";
cerr << *currentThread;
cerrLock.release();
}
#endif /* NDEBUG */
raisedBy = ExceptionSwitch;
raise();
}
}
else {
//
// unsafe to add to current events, but then again, there's nothing
// to do, so don't raise an exception.
//
}
}
//
// This is the job dispatcher.
//
void
HardwareCpu::stirItAround()
{
currentThread = 0;
while( ! SimulationTerminated ) {
if ( currentThread == 0 ) {
currentThread = remove();
}
if ( currentThread != 0 ) {
#ifndef NDEBUG
if (HardwareDebugFlag || currentThread -> debug()) {
cerrLock.reserve();
cerr << name << " switch to " << *currentThread << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
systemContext.switchContext(&(currentThread -> pContext));
if ( currentThread != 0 &&
(HardwareDebugFlag || currentThread -> debug() )) {
cerr << name << " Raise by " << *currentThread << "\n";
}
//
// Come back here because of an exception
//
switch (raisedBy) {
case ExceptionReserve :
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "reserve exception\n";
cerrLock.release();
}
#endif /* NDEBUG */
bool blocked =
reserveToBlockOn -> reserveByException( currentThread );
if ( blocked ) {
currentThread = 0;
}
break;
case ExceptionDelay:
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "delay exception for ";
cerr << timeToDelay << "\n";
cerrLock.release();
}
#endif /* NDEBUG */
add( currentThread, timeToDelay );
currentThread = 0;
break;
case ExceptionSwitch:
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << " switch exception\n";
cerrLock.release();
}
#endif /* NDEBUG */
currentThread = 0;
break;
case ExceptionTerminateThread:
#ifndef NDEBUG
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "termination exception for ";
cerr << hex(long(threadToTerminate)) << "\n";
cerr << *threadToTerminate <<"\n";
cerrLock.release();
}
#endif /* NDEBUG */
if ( threadToTerminate == currentThread ) {
currentThread = 0;
delete threadToTerminate;
}
else {
delete threadToTerminate;
}
break;
default:
cerrLock.reserve();
cerr << name << "Unknown exception:";
cerr << int(raisedBy) << "\n";
cerrLock.release();
exit(1);
break;
}
}
}
}
@
1.2
log
@*** empty log message ***
@
text
@d2 1
a8 2
#include "SharedMemory.h"
#include "SharedMalloc.h"
d45 6
d71 3
a73 3
static HardSpinLock CurrentEventsLock[HardwareCpusMax];
static int CurrentEventsCounter[HardwareCpusMax];
static ThreadContainer *CurrentEvents[HardwareCpusMax];
d78 1
a78 1
static AwesimeHeap *PendingEvents[HardwareCpusMax];
d176 4
d191 1
d497 3
a499 3
// Ok, we've decided that there's nothing for us to do,
// and there's nothing for anyone else to do either (maybe).
// So we need to decide if we're going to advance time or not.
d590 1
d596 1
d604 1
a604 3
rendezvous();
if (iYam == 0) {
d627 2
a628 2
// This can't cause race conditions because we only
// use this info in the ``rendevzous to advance time''
d815 5
a895 6
}
ThreadContainer *
AllocateHardwareCurrentEventsStructure()
{
return( new HeapScheduler(32) );
@
1.1
log
@Initial revision
@
text
@d3 1
d10 1
d28 1
d57 4
a60 3
static HardSpinLock CurrentEventsLock;
static int SimulationTerminated = 0;
static HeapScheduler CurrentEvents;
d62 7
a68 2
static HardSpinLock PendingEventsLock;
static AwesimeHeap PendingEvents;
d70 6
a76 2
static int TimeAdvanceCounter = 0;
static HardSpinLock TimeAdvanceCounterLock;
d78 2
d83 1
a83 1
static HardwareDebugFlag = 0;
d91 1
a91 1
name = "[HardwareCpu-0] ";
d117 50
a172 1
CpuBarrier.height(cpus);
d174 1
d180 1
a182 1
HardwareMemoryAllocator.disableFurtherBreaks();
d190 1
d196 11
a206 7
for (int whoAmI = HardwareCpus - 1; whoAmI > 0; whoAmI--) {
int pid = fork();
if (pid == 0) {
iYam = whoAmI;
sprintf(nameSpace, "[HardwareCpu-%d] ", whoAmI);
name = nameSpace;
break;
d210 1
d216 2
d258 1
d264 1
d268 15
a282 3
CurrentEventsLock.reserve();
CurrentEvents.add( who );
CurrentEventsLock.release();
d285 1
d291 1
d296 1
a296 3
PendingEventsLock.reserve();
PendingEvents.add( AwesimeHeapItem(when, who) );
PendingEventsLock.release();
d300 4
d308 1
a308 1
// Just for safety
d310 13
a322 6
PendingEventsLock.reserve();
CurrentEventsLock.reserve();
AwesimeHeapItem item;
int validItem = PendingEvents.remove( item );
d328 1
a328 4
double when = item.key();
assert( CurrentSimulatedTime <= when );
CurrentSimulatedTime = when;
d334 1
d336 2
a337 28
CurrentEvents.add( (Thread*) item.ptr() );
//
// Now that we know the time of the minimum entry in the
// heap, remove all the events which occur at that time
// or before that time (actually, that is an error).
//
// This allows the items that occur at the same time
// (in the heap) to be ordered in the subscheduler
// according to the constraints of the subscheduler
// (.e.g heapscheduler).
//
// If we did not pull out all items for the current time,
// it is possible that a threads will execute out of
// priority order. This could be fixed by making the
// ThreadHeap properly order events, but that also
// means we have got a single central data structure,
// and there will be more contention.
//
for (AwesimeHeapIndex index = PendingEvents.minItem();
index != AwesimeHeapNull
&& PendingEvents.item(index).key() <= when;
index = PendingEvents.minItem() )
{
bool removed = PendingEvents.remove(item);
assert( removed );
CurrentEvents.add((Thread *) item.ptr());
}
a338 1
d340 1
a340 1
// Should be save to do this -- everyone is waiting for the master
d343 2
a344 1
d350 3
a352 8
TimeAdvanceCounter = 0;
//
// Release the locks on the two data structures
//
CurrentEventsLock.release();
PendingEventsLock.release();
d362 1
d368 1
d370 6
a375 5
CurrentEventsLock.reserve();
while ( CurrentEvents.isEmpty() ) {
CurrentEventsLock.release();
d377 1
d383 1
d386 5
a390 5
TimeAdvanceCounterLock.reserve();
TimeAdvanceCounter++;
d393 3
a395 2
cerr << name << "increment time advance counter to";
cerr << TimeAdvanceCounter << "\n";
d398 9
a406 13
assert(TimeAdvanceCounter <= HardwareCpus);
TimeAdvanceCounterLock.release();
//
// Now, wait for either of TimeAdvanceCounter == HardwareCpus,
// for a new event
int goAdvanceTime = 0;
int lookForEvent = 0;
do {
d409 2
a410 1
cerr << name << "reserve CurrentEventsLock\n";
d413 70
a482 5
CurrentEventsLock.reserve();
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "reserve TimeAdvanceCounterLock\n";
cerrLock.release();
d484 9
a492 16
TimeAdvanceCounterLock.reserve();
lookForEvent = !CurrentEvents.isEmpty() || SimulationTerminated;
goAdvanceTime = !lookForEvent
&& TimeAdvanceCounter == HardwareCpus;
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "lookForEvent = " << int(lookForEvent);
cerr << " and goAdvanceTime == " << int(goAdvanceTime);
cerr << " and TimeAdvanceCounter = " << TimeAdvanceCounter;
cerr << "\n";
cerrLock.release();
}
if (lookForEvent) {
d495 2
a496 1
cerr << name << "decrement TimeAdvanceCounter\n";
d498 124
a621 3
}
TimeAdvanceCounter--;
}
d623 25
a647 2
TimeAdvanceCounterLock.release();
CurrentEventsLock.release();
d649 2
a650 1
} while ( !( goAdvanceTime || lookForEvent ) );
d652 3
a654 8
assert( (goAdvanceTime && !lookForEvent)
|| (lookForEvent && !goAdvanceTime) );
if (lookForEvent) {
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "decided to look for event\n";
cerrLock.release();
a655 2
CurrentEventsLock.reserve();
continue; /* while CurrentEvents.isEmpty() */
d657 1
a657 15
//
// Nothing is locked at this point.
//
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "rendezvous to advance time\n";
cerrLock.release();
}
rendezvous();
if (iYam == 0) {
advanceTime();
}
rendezvous();
d659 1
a659 5
//
// reserve for next trip around loop
//
CurrentEventsLock.reserve();
}
d661 5
a665 3
if ( SimulationTerminated ) {
CurrentEventsLock.release();
return(0);
d667 3
a669 15
else {
//
// We have the CurrentEventsLock & there should be someone there.
//
Thread *newGuy = CurrentEvents.remove();
CurrentEventsLock.release();
if (HardwareDebugFlag) {
cerrLock.reserve();
cerr << name << "find " << hex(long(newGuy)) << "\n";
cerrLock.release();
}
return( newGuy );
}
a674 1
CurrentEventsLock.reserve();
a675 1
CurrentEventsLock.release();
a687 7
void
HardwareCpu::reserveByException( ReserveByException *sem )
{
raisedBy = ExceptionReserve;
reserveToBlockOn = sem;
raise();
}
d690 1
a690 1
HardwareCpu::threadTerminateException( Thread *killMe )
d692 4
a695 4
raisedBy = ExceptionTerminateThread;
threadToTerminate = killMe;
raise();
}
d697 80
a776 6
void
HardwareCpu::delayException( double howLong )
{
raisedBy = ExceptionDelay;
timeToDelay = howLong;
raise();
d796 1
d802 1
d811 1
d817 1
d826 1
d833 1
d838 12
d851 1
d859 1
d881 6
@